package wechat

import (
	"context"
	"encoding/json"
	"fmt"
	"gitee.com/DonHz/basic-go/webook/internal/domain"
	"gitee.com/DonHz/basic-go/webook/pkg/logger"
	"go.uber.org/zap"
	"net/http"
	"net/url"
)

var redirectURL = url.PathEscape("https://hertzDun.com/oauth2/wechat/callback")

type Service interface {
	AuthURL(ctx context.Context, state string) (string, error)
	VerifyCode(ctx context.Context, code string) (domain.WechatInfo, error)
}

type AuthUrlService struct {
	appId string
	appSecret string
	client *http.Client
	l logger.Logger
}

func NewAuthUrlService(appId string, appSecret string, client *http.Client, l logger.Logger) Service{
	return &AuthUrlService{
		appId: appId,
		appSecret: appSecret,
		client: client,
		l: l,
	}
}

func (s *AuthUrlService) AuthURL(ctx context.Context, state string) (string, error) {
	const urlPattern = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_login&state=%s#wechat_redirect"
	// 需要是自己注册好的域名
	return fmt.Sprintf(urlPattern, s.appId, redirectURL, state), nil
}

func (s *AuthUrlService) VerifyCode(ctx context.Context, code string) (domain.WechatInfo, error) {
	 const targetURLPattern = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"
	 target:=fmt.Sprintf(targetURLPattern, s.appId, s.appSecret, code)
	 req, err:=http.NewRequestWithContext(ctx, http.MethodGet, target, nil)
	 if err!=nil {
		 return domain.WechatInfo{}, err
	 }
	 resp, err:=s.client.Do(req)
	 if err!= nil{
		 return domain.WechatInfo{}, err
	 }
	 decoder:=json.NewDecoder(resp.Body)
	 var res Result
	 err = decoder.Decode(&res)
	 // 不推荐的写法
	 //body, err:=io.ReadAll(resp.Body)
	 //err=json.Unmarshal(body, &res)
	 if err!=nil {
		 return domain.WechatInfo{}, err
	 }
	 if res.ErrCode!=0{
		 return domain.WechatInfo{},
		 fmt.Errorf("微信返回错误响应，错误码：%d，错误信息：%s",res.ErrCode, res.ErrMsg)
	 }
	 zap.L().Info("调用微信，拿到用户信息", zap.String("unionID", res.UnionID),
		 zap.String("openID", res.OpenID))
	 return domain.WechatInfo{
		OpenID: res.OpenID,
		UnionID: res.UnionID,
	 }, nil
}

type Result struct {
	ErrCode int64 `json:"errcode"`
	ErrMsg string `json:"errmsg"`

	AccessToken string `json:"access_token"`
	ExpiresIn int64 `json:"expires_in"`
	RefreshToken string `json:"refresh_token"`

	OpenID string `json:"openid"`
	Scope string `json:"scope"`
	UnionID string `json:"unionid"`
}